package com.healthcloud.shiro;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.healthcloud.utils.ApiRes;

import org.apache.oltu.oauth2.common.OAuth;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.CacheManagerAware;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpStatus;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import java.io.PrintWriter;

/**
 * oauth 授权过滤器 <p/> Created by xiam on 2015/6/12.
 */
public class OAuthTokenFilter extends FormAuthenticationFilter implements CacheManagerAware,
		InitializingBean {

	private static final Logger log = LoggerFactory.getLogger(OAuthTokenFilter.class);

	public static final String DEFAULT_TOKEN_CACHE_NAME = "token_cache";

	private CacheManager cacheManager;

	private Cache<String, OauthSubjectWrapper> cache;

	private ObjectMapper objectMapper;

	@Override
	public void setCacheManager(CacheManager cacheManager) {
		this.cacheManager = cacheManager;
	}

	public void setObjectMapper(ObjectMapper objectMapper) {
		this.objectMapper = objectMapper;
	}

	/**
	 * 根据token判断是否有权访问
	 *
	 * @param request
	 * @param response
	 * @param mappedValue
	 * @return
	 */
	@Override
	protected boolean isAccessAllowed(ServletRequest request, ServletResponse response,
			Object mappedValue) {
		System.out.println(request.getParameter("idCard"));
		String token = request.getParameter(OAuth.OAUTH_ACCESS_TOKEN);
		if (token != null) {
			OauthSubjectWrapper wrapper = cache.get(token);
			if (wrapper == null) {
				ApiRes msg = new ApiRes(false, null, "invalid_token", null);
				output(response, msg, HttpStatus.FORBIDDEN.value());
				return false;
			}
			Subject subject = wrapper.getSubject();
			boolean authenticated = subject.isAuthenticated();
			if (!authenticated) {
				cache.remove(token);
				ApiRes msg = new ApiRes(false, null, "expired_token", null);
				output(response, msg, HttpStatus.FORBIDDEN.value());
				return false;
			}
			return authenticated;
		}
		ApiRes msg = new ApiRes(false, null, "missing_token", null);
		output(response, msg, HttpStatus.FORBIDDEN.value());
		return false;
	}

	@Override
	protected boolean isRememberMe(ServletRequest request) {
		return false;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		if (cacheManager == null) {
			throw new IllegalArgumentException("Cache manager must not null.");
		}
		this.cache = this.cacheManager.getCache(DEFAULT_TOKEN_CACHE_NAME);
		if (this.objectMapper == null) {
			objectMapper = new ObjectMapper();
		}
	}

	private void output(ServletResponse response, Object msg, int status) {
		PrintWriter writer = null;
		try {
			HttpServletResponse httpServletResponse = (HttpServletResponse) response;
			httpServletResponse.setStatus(status);
			writer = response.getWriter();
			String string = objectMapper.writeValueAsString(msg);
			writer.write(string);
			writer.flush();
			writer.close();
		}
		catch (Exception e) {
			log.error(e.getMessage(), e.getCause());
		}
		finally {
			if (writer != null) {
				writer.close();
			}
		}
	}

}
